package com.example.framework.view;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.RejectedExecutionException;

import com.example.framework.base.CustomApplication;
import com.example.framework.base.ImageCache;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

public class CustomImageView extends ImageView
{
	private Context mContext;

	private static final int MAX_FAILURES = 3;

	private int mFailure;

	private String mUrl;

	private String mCurrentlyGrabbedUrl;

	private float mImageCacheSize = 1;

	private final static long MB = 1048576;

	public CustomImageView(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
		mContext = context;

	}

	public CustomImageView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		mContext = context;
	}

	public CustomImageView(Context context)
	{
		super(context);
		mContext = context;
	}

	public void setDefaultImage(int resid)
	{
		setImageResource(resid);
	}

	/**
	 * Set image by offered URL.On the one hand,image can get from cache,on the
	 * other hand,get from network by URL.
	 */
	public void setImageUrl(String url)
	{
		if (mUrl != null && mUrl.equals(url) && (mCurrentlyGrabbedUrl == null || (mCurrentlyGrabbedUrl != null && !mCurrentlyGrabbedUrl.equals(url))))
		{
			mFailure++;
			if (mFailure > MAX_FAILURES)
			{
				Log.e(CustomApplication.IMAGECACHE_TAG, "Download image failed:" + url);
				return;
			}
		}
		else
		{

			mUrl = url;
			mFailure = 0;
		}

		ImageCache imageCache = CustomApplication.getInstance().getImageCache();

		if (imageCache.isCached(url))
		{
			setImageBitmap(imageCache.get(url));
			Log.i(CustomApplication.IMAGECACHE_TAG, "Load image from cache.");
		}
		else
		{
			String fileName = convertUrlToFileName(url);
			String pathFileName = getDirectory(fileName);

			File pathFile = new File(pathFileName);
			if (!pathFile.exists())
			{
				try
				{
					pathFile.createNewFile();
				}
				catch (IOException e)
				{
					Log.d(CustomApplication.IMAGECACHE_TAG, "create image file failed:" + pathFileName);
				}
			}

			Bitmap tbmp = BitmapFactory.decodeFile(pathFileName);

			if (tbmp == null)
			{
				Log.d(CustomApplication.IMAGECACHE_TAG, "Image not exists,now to download by asynctask!");
				try
				{
					new DownloadTask().execute(url);
				}
				catch (RejectedExecutionException e)
				{
					Log.d(CustomApplication.IMAGECACHE_TAG, "Download failed.");
				}
			}
			else
			{
				Log.i(CustomApplication.IMAGECACHE_TAG, "Load image from the existing file");
				CustomApplication.getInstance().getImageCache().put(url, tbmp);
				mCurrentlyGrabbedUrl = url;
				this.setImageBitmap(tbmp);
			}

			updateCacheSize();
		}

	}

	/**
	 * 
	 */
	private void updateCacheSize()
	{
		mImageCacheSize = PreferenceManager.getDefaultSharedPreferences(mContext).getFloat(CustomApplication.CACHE_SIZE, CustomApplication.IMAGE_DEFAULT_CACHE);

		if (isSDCardEnable())
		{
			String extStorageDirectory = Environment.getExternalStorageDirectory().toString();

			String dirPath = extStorageDirectory + CustomApplication.CACHE_DIR + "ImageCache";

			File dirFile = new File(dirPath);

			File[] files = dirFile.listFiles();

			long dirSize = 0;

			for (File file : files)
			{

				dirSize += file.length();
			}

			if (dirSize > mImageCacheSize * MB)
			{
				clearCache();
			}
		}

	}

	class DownloadTask extends AsyncTask<String, Void, String>
	{

		private String mTaskUrl;
		private Bitmap mBmp = null;

		@Override
		public void onPreExecute()
		{
			super.onPreExecute();
		}

		@Override
		public String doInBackground(String... params)
		{

			mTaskUrl = params[0];
			InputStream stream = null;
			URL imageUrl;
			Bitmap bmp = null;

			try
			{
				imageUrl = new URL(mTaskUrl);
				try
				{
					stream = imageUrl.openStream();
					bmp = BitmapFactory.decodeStream(stream);
					try
					{
						if (bmp != null)
						{
							mBmp = bmp;
							CustomApplication.getInstance().getImageCache().put(mTaskUrl, bmp);
							Log.d(CustomApplication.IMAGECACHE_TAG, "save image to application's cache: " + mTaskUrl);

						}
					}
					catch (NullPointerException e)
					{
						Log.w(CustomApplication.IMAGECACHE_TAG, "can't find image by this url:" + mTaskUrl);
					}
				}
				catch (IOException e)
				{
					Log.w(CustomApplication.IMAGECACHE_TAG, "can't load this url:" + mTaskUrl);
				}
				finally
				{
					try
					{
						if (stream != null)
						{
							stream.close();
						}
					}
					catch (IOException e)
					{
					}
				}

			}
			catch (MalformedURLException e)
			{
				e.printStackTrace();
			}
			return mTaskUrl;
		}

		@Override
		public void onPostExecute(String url)
		{
			super.onPostExecute(url);

			Bitmap bmp = CustomApplication.getInstance().getImageCache().get(url);
			if (bmp == null)
			{
				Log.w(CustomApplication.IMAGECACHE_TAG, "reloading:" + url);
				CustomImageView.this.setImageUrl(url);
			}
			else
			{

				CustomImageView.this.setImageBitmap(bmp);
				mCurrentlyGrabbedUrl = url;
				saveBmpToSd(mBmp, url);

			}
		}

	};

	private void saveBmpToSd(Bitmap bm, String url)
	{

		if (bm == null)
		{
			return;
		}

		if (mImageCacheSize == 0)
		{
			return;
		}

		String filename = convertUrlToFileName(url);
		String dir = getDirectory(filename);
		File file = new File(dir);

		try
		{
			file.createNewFile();
			OutputStream outStream = new FileOutputStream(file);
			bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
			outStream.flush();
			outStream.close();

			Log.i(CustomApplication.IMAGECACHE_TAG, "image has been saved to SD card.");

		}
		catch (FileNotFoundException e)
		{
			Log.w(CustomApplication.IMAGECACHE_TAG, "can't find file catalog!");

		}
		catch (IOException e)
		{
			Log.w(CustomApplication.IMAGECACHE_TAG, e.toString());
		}

	}

	private String convertUrlToFileName(String url)
	{
		String filename = url;
		filename = filename.replace("http://", "");
		filename = filename.replace("/", ".");
		filename = filename.replace(":", ".");
		filename = filename.replace("jpg", "dat");
		filename = filename.replace("png", "dat");
		return filename;
	}

	private String getDirectory(String filename)
	{

		String extStorageDirectory = Environment.getExternalStorageDirectory().toString();

		String dirPath = extStorageDirectory + CustomApplication.CACHE_DIR + "ImageCache";

		File dirFile = new File(dirPath);

		if (!dirFile.exists())
		{
			dirFile.mkdirs();
		}
		return dirPath + "/" + filename;

	}

	private void clearCache()
	{

		if (isSDCardEnable())
		{
			String extStorageDirectory = Environment.getExternalStorageDirectory().toString();

			String dirPath = extStorageDirectory + CustomApplication.CACHE_DIR + "ImageCache";

			File dir = new File(dirPath);

			File[] files = dir.listFiles();

			if (files == null || files.length == 0)
			{
				return;
			}

			for (File file : files)
			{
				file.delete();
			}

			Log.d(CustomApplication.IMAGECACHE_TAG, "cleared cache:" + dirPath);
		}
	}

	public static boolean isSDCardEnable()
	{

		return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
	}

}
